package org.ponly.cta4j.drawing.text;

import java.awt.*;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Container class for a list of GlyphVector.
 *
 * @author mag
 * @since 1.0
 */
public class Glyphs implements Iterable<GlyphVector> {
    private final List<GlyphVector> vectors = new ArrayList<GlyphVector>();

    /**
     * 向当前容器中添加 glyph vector.
     *
     * @param glyph glyph
     */
    public void addGlyphVector(final GlyphVector glyph) {
        this.vectors.add(glyph);
    }

    /**
     * 获取当前容器中的 GlyphVector 数量.
     *
     * @return 容器大小
     */
    public int size() {
        return vectors.size();
    }

    /**
     * 获取索引为 index 的 GlyphVector 实例.
     *
     * @param index 索引
     * @return GlyphVector
     */
    public GlyphVector get(final int index) {
        return this.vectors.get(index);
    }

    /**
     * 获取索引为 index 的 GlyphVector 实例的边界 X 坐标.
     *
     * @param index 索引
     * @return X 坐标
     */
    public double getBoundsX(final int index) {
        return getBounds(index).getX();
    }

    /**
     * 获取索引为 index 的 GlyphVector 实例的边界 Y 坐标.
     *
     * @param index 索引
     * @return Y 坐标
     */
    public double getBoundsY(final int index) {
        return getBounds(index).getY();
    }

    /**
     * 获取索引为 index 的 GlyphVector 实例的边界宽度.
     *
     * @param index 索引
     * @return 宽度
     */
    public double getBoundsWidth(final int index) {
        return getBounds(index).getWidth();
    }

    /**
     * 获取索引为 index 的 GlyphVector 实例的边界高度.
     *
     * @param index 索引
     * @return 高度
     */
    public double getBoundsHeight(final int index) {
        return getBounds(index).getHeight();
    }

    /**
     * 获取索引为 index 的 GlyphVector 的 X 坐标.
     *
     * @param index 索引
     * @return X 坐标
     */
    public double getX(final int index) {
        return get(index).getGlyphPosition(0).getX();
    }

    /**
     * 获取索引为 index 的 GlyphVector 的 Y 坐标.
     *
     * @param index 索引
     * @return Y 坐标
     */
    public double getY(final int index) {
        return get(index).getGlyphPosition(0).getY();
    }

    /**
     * 获取 outline.
     *
     * @param index 索引
     * @return outline
     */
    public Shape getOutline(final int index) {
        return get(index).getOutline();
    }

    /**
     * @return 边界的 X 坐标
     */
    public double getBoundsX() {
        return getBounds().getX();
    }

    /**
     * @return 边界的 Y 坐标
     */
    public double getBoundsY() {
        return getBounds().getY();
    }

    /**
     * @return 边界的宽度
     */
    public double getBoundsWidth() {
        return getBounds().getWidth();
    }

    /**
     * @return 边界的高度
     */
    public double getBoundsHeight() {
        return getBounds().getHeight();
    }

    /**
     * @param index 索引
     * @return 获取边界范围内的最大X坐标
     */
    public double getMaxX(final int index) {
        return getBounds(index).getMaxX();
    }

    /**
     * @param index 索引
     * @return 获取边界范围内的最大Y坐标
     */
    public double getMaxY(final int index) {
        return getBounds(index).getMaxY();
    }

    /**
     * @param index 索引
     * @return 获取边界范围内的最小X坐标
     */
    public double getMinX(final int index) {
        return getBounds(index).getMinX();
    }

    /**
     * @param index 索引
     * @return 获取边界范围内的最小Y坐标
     */
    public double getMinY(final int index) {
        return getBounds(index).getMinX();
    }

    /**
     * 获取边界区域.
     *
     * @param index 索引
     * @return 边界区域
     */
    public Rectangle2D getBounds(final int index) {
        return this.vectors.get(index).getVisualBounds();
    }

    /**
     * 获取边界区域.
     *
     * @return 边界区域
     */
    public Rectangle2D getBounds() {
        Rectangle2D bounds = size() > 0 ? getBounds(0) : new Rectangle2D.Double(0, 0, 0, 0);
        for (int i = 1; i < size(); i++) {
            bounds = bounds.createUnion(getBounds(i));
        }
        return bounds;
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return Metrics
     */
    public GlyphMetrics getMetrics(final int index) {
        return get(index).getGlyphMetrics(0);
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return LSB
     */
    public double getLSB(final int index) {
        return getMetrics(index).getLSB();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return RSB
     */
    public double getRSB(final int index) {
        return getMetrics(index).getRSB();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return Advance
     */
    public double getAdvance(final int index) {
        return getMetrics(index).getAdvance();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部宽度
     */
    public double getInternalWidth(final int index) {
        return getAdvance(index) - getRSB(index) - getLSB(index);
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部区域范围
     */
    public Rectangle2D getInternalBounds(final int index) {
        return getMetrics(index).getBounds2D();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部范围X坐标
     */
    public double getInternalBoundsX(final int index) {
        return getInternalBounds(index).getX();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部范围Y坐标
     */
    public double getInternalBoundsY(final int index) {
        return getInternalBounds(index).getY();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部范围宽度
     */
    public double getInternalBoundsWidth(final int index) {
        return getInternalBounds(index).getWidth();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return 内部范围高度
     */
    public double getInternalBoundsHeight(final int index) {
        return getInternalBounds(index).getHeight();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return AdvanceX
     */
    public double getAdvanceX(final int index) {
        return getMetrics(index).getAdvanceX();
    }

    /**
     * TODO doc me.
     *
     * @param index 索引
     * @return AdvanceY
     */
    public double getAdvanceY(final int index) {
        return getMetrics(index).getAdvanceY();
    }

    /**
     * @return 最大高度
     */
    public double getMaxHeight() {
        double max = 0;
        for (int i = 1; i < size(); i++) {
            max = Math.max(getBoundsHeight(i), max);
        }
        return max;
    }

    /**
     * @return 最大宽度
     */
    public double getMaxWidth() {
        double max = 0;
        for (int i = 1; i < size(); i++) {
            max = Math.max(getBoundsWidth(i), max);
        }
        return max;
    }

    /**
     * 对所有移动位置.
     *
     * @param x X 偏移量
     * @param y Y 偏移量
     */
    public void translate(final double x, final double y) {
        for (int i = 0; i < size(); i++) {
            translate(i, x, y);
        }
    }

    /**
     * 移动位置.
     *
     * @param index 索引
     * @param x     X 偏移量
     * @param y     Y 偏移量
     */
    public void translate(final int index, final double x, final double y) {
        setPosition(index, x + getX(index), y + getY(index));
    }

    /**
     * 设置位置.
     *
     * @param index 索引
     * @param x     X 坐标
     * @param y     Y 坐标
     */
    public void setPosition(final int index, final double x, final double y) {
        vectors.get(index).setGlyphPosition(0, new Point2D.Double(x, y));
    }

    /**
     * 对所有 GlyphVector 增加 AffineTransform.
     *
     * @param at AffineTransform
     */
    public void addAffineTransform(final AffineTransform at) {
        for (int i = 0; i < size(); i++) {
            addAffineTransform(i, at);
        }
    }

    /**
     * 对 index 处 GlyphVector 增加 AffineTransform.
     *
     * @param index 目标索引
     * @param at    AffineTransform
     */
    public void addAffineTransform(final int index, final AffineTransform at) {
        AffineTransform t = vectors.get(index).getGlyphTransform(0);
        if (t == null) {
            t = at;
        } else {
            t.concatenate(at);
        }
        vectors.get(index).setGlyphTransform(0, t);
    }

    /**
     * 旋转给定索引对应的 GlyphVector angle 度.
     *
     * @param index 索引
     * @param angle 旋转角度
     */
    public void rotate(final int index, final double angle) {
        get(index).setGlyphTransform(0, AffineTransform.getRotateInstance(
                angle,
                getBoundsX(index) + getBoundsWidth(index) / 2,
                getBoundsY(index) + getBoundsHeight(index) / 2)
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        final StringBuilder buf = new StringBuilder();
        buf.append("{Glyphs=");
        for (int i = 0; i < size(); i++) {
            buf.append("\n\t");
            buf.append("{GlyphVector=").append(i).append(" : ");

            for (int j = 0; j < this.get(i).getNumGlyphs(); j++) {

                buf.append("Glyph=").append(j);

                buf.append("; Bounds=");
                buf.append(this.get(i).getGlyphVisualBounds(j).getBounds2D());
                buf.append("; Font=");
                buf.append(this.get(i).getFont());
            }


            buf.append('}');

        }
        buf.append('\n');
        buf.append("Bounds : ");
        buf.append(this.getBounds());
        buf.append('}');
        return buf.toString();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<GlyphVector> iterator() {
        return vectors.iterator();
    }
}
